﻿using System;
using System.Collections.Generic;
using System.Text;

namespace Flagwind.Data
{
	public delegate Command ChildFunc(Command parent);

	public delegate Command CacheFunc(object paraValueObject);

	public delegate void OrderAction(SortOrder order);

	public delegate void OrderAction<T>(SortOrder order, T para) where T : class;

	public class Command : ICommand, IDisposable
	{
		/// <summary>
		/// SqlServer上的锁类型枚举。请注意，Command应用这个枚举之后将只能在SqlServer上面使用。
		/// </summary>
		public enum SqlServerLock
		{
			/// <summary>
			/// 在该表上保持共享锁，直到整个事务结束，而不是在语句执行完立即释放所添加的锁。
			/// </summary>
			HOLDLOCK,

			/// <summary>
			/// 不添加共享锁和排它锁，当这个选项生效后，可能读到未提交读的数据或“脏数据”，这个选项仅仅应用于SELECT语句
			/// </summary>
			NOLOCK,

			/// <summary>
			/// 指定添加页锁（否则通常可能添加表锁）
			/// </summary>
			PAGLOCK,

			/// <summary>
			/// 用与运行在提交读隔离级别的事务相同的锁语义执行扫描。默认情况下，SQL Server 2000 在此隔离级别上操作
			/// </summary>
			READCOMMITTED,

			/// <summary>
			/// 跳过已经加锁的数据行，这个选项将使事务读取数据时跳过那些已经被其他事务锁定的数据行，而不是阻塞直到其他事务释放锁，READPAST仅仅应用于READ COMMITTED隔离性级别下事务操作中的SELECT语句操作
			/// </summary>
			READPAST,

			/// <summary>
			/// 等同于NOLOCK
			/// </summary>
			READUNCOMMITTED,

			/// <summary>
			/// 设置事务为可重复读隔离性级别
			/// </summary>
			REPEATABLEREAD,

			/// <summary>
			/// 使用行级锁，而不使用粒度更粗的页级锁和表级锁
			/// </summary>
			ROWLOCK,

			/// <summary>
			/// 用与运行在可串行读隔离级别的事务相同的锁语义执行扫描。等同于 HOLDLOCK。
			/// </summary>
			SERIALIZABLE,

			/// <summary>
			/// 指定使用表级锁，而不是使用行级或页面级的锁，SQL Server在该语句执行完后释放这个锁，而如果同时指定了HOLDLOCK，该锁一直保持到这个事务结束
			/// </summary>
			TABLOCK,

			/// <summary>
			/// 指定在表上使用排它锁，这个锁可以阻止其他事务读或更新这个表的数据，直到这个语句或整个事务结束
			/// </summary>
			TABLOCKX,

			/// <summary>
			/// 指定在读表中数据时设置更新 锁（update lock）而不是设置共享锁，该锁一直保持到这个语句或整个事务结束，使用UPDLOCK的作用是允许用户先读取数据（而且不阻塞其他用户读数据），并且保证在后来再更新数据时，这一段时间内这些数据没有被其他用户修改
			/// </summary>
			UPDLOCK,

			/// <summary>
			/// 未知（Command默认）
			/// </summary>
			UNKNOW
		}

		#region 分页相关

		/// <summary>
		/// 查询前N条记录，目前仅支持Access/SqlServer，其它数据库可以使用Limit(N) 方法替代。
		/// </summary>
		public int TopCount = 0;

		/// <summary>
		/// 是否开启分页功能，如果启用，Command不能设定“排序”信息，分页标识字段将作为排序字段
		/// </summary>
		public bool PageEnable = false;

		/// <summary>
		/// 分页时候每页的记录大小，默认为10
		/// </summary>
		public int PageSize = 10;

		/// <summary>
		/// 分页时候的当前页码，默认为1
		/// </summary>
		public int PageIndex = 1;

		/// <summary>
		/// 分页时候的记录标识字段，默认为主键字段。不支持多主键。
		/// </summary>
		public string PageField = "";

		/// <summary>
		/// 分页的时候记录按照倒序排序（对Oracle数据库不起效）
		/// </summary>
		public bool PageOrderDesc = true;

		/// <summary>
		/// 分页的时候，记录的总数量。
		/// </summary>
		public int RecordCount = 0;

		/// <summary>
		/// 是否排除重复记录
		/// </summary>
		public bool Distinct;

		/// <summary>
		/// 限制查询的记录数量，对于SQLSERVER/ACCESS，将采用主键作为标识的高速分页方式。
		/// 注：调用该方法不会影响生Command.ToString()结果，仅在最终执行查询的时候才会去构造当前特点数据库的SQL语句。
		/// </summary>
		/// <param name="pageSize">页大小</param>
		/// <returns></returns>
		public Command Limit(int pageSize)
		{
			this.PageEnable = true;
			this.PageSize = pageSize;
			return this;
		}

		/// <summary>
		/// 限制查询的记录数量，对于SQLSERVER/ACCESS，将采用主键作为标识的高速分页方式。
		/// 注：调用该方法不会影响生Command.ToString()结果，仅在最终执行查询的时候才会去构造当前特点数据库的SQL语句。
		/// </summary>
		/// <param name="pageSize">页大小</param>
		/// <param name="pageNumber">页号码</param>
		/// <returns></returns>
		public Command Limit(int pageSize, int pageNumber)
		{
			this.PageEnable = true;
			this.PageSize = pageSize;
			this.PageIndex = pageNumber;
			return this;
		}

		/// <summary>
		/// 限制查询的记录数量，对于SQLSERVER/ACCESS，将采用主键作为标识的高速分页方式。
		/// 注：调用该方法不会影响生Command.ToString()结果，仅在最终执行查询的时候才会去构造当前特点数据库的SQL语句。
		/// </summary>
		/// <param name="pageSize">页大小</param>
		/// <param name="pageNumber">页号码</param>
		/// <param name="autoRecCount">是否允许自动查询本次分页查询前的记录总数，
		/// 如果允许，那么查询成功后可以从Command对象的PageWithAllRecordCount 字段得到实际的记录数量</param>
		/// <returns></returns>
		public Command Limit(int pageSize, int pageNumber, bool autoRecCount)
		{
			this.PageEnable = true;
			this.PageSize = pageSize;
			this.PageIndex = pageNumber;
			if(autoRecCount)
			{
				this.RecordCount = 0;
			}
			return this;
		}

		/// <summary>
		/// 限制查询的记录数量，对于SQLSERVER/ACCESS，将采用指定字段作为标识的高速分页方式。
		/// 注：调用该方法不会影响生Command.ToString()结果，仅在最终执行查询的时候才会去构造当前特点数据库的SQL语句。
		/// </summary>
		/// <param name="pageSize">页大小</param>
		/// <param name="pageNumber">页号码</param>
		/// <param name="pageField">要排序的字段</param>
		/// <returns></returns>
		public Command Limit(int pageSize, int pageNumber, string pageField)
		{
			this.PageEnable = true;
			this.PageSize = pageSize;
			this.PageIndex = pageNumber;
			this.PageField = pageField;
			return this;
		}

		#endregion

		#region 旧版本保留的变量定义

		/// <summary>
		/// 当前实体类
		/// </summary>
		protected internal IEntity currEntity;

		/// <summary>
		/// 是否已经发生了连接操作
		/// </summary>
		protected internal bool haveJoinOpt;

		/// <summary>
		/// 是否有排序操作
		/// </summary>
		protected internal bool haveOrderBy;

		/// <summary>
		/// SQL选择的字段
		/// </summary>
		protected internal string sql_fields = string.Empty;

		/// <summary>
		/// 查询对应的表
		/// </summary>
		protected internal string sql_table = string.Empty;

		/// <summary>
		/// 查询条件
		/// </summary>
		protected internal string sql_condition = string.Empty;

		#endregion

		#region 新增变量定义

		private const int Command_SELECT = 1, Command_UPDATE = 2, Command_INSERT = 3, Command_DELETE = 4, Command_INSERT_FROM = 5, Command_UPDATE_SELFT = 6;
		private Dictionary<object, string> dictAliases = null;
		private string mainTableName = "";
		private List<string> selectedFieldNames = new List<string>();
		private List<string> _groupbyFieldNames;
		private string sql_from = string.Empty; //Select时候的表名或者Upate，Insert的前缀语句
		private char updateSelfOptChar;
		private int paraIndex = 0;
		private int optFlag = Command_SELECT;
		private Command insertFromCommand = null;
		private Command parentCommand = null;
		private int fieldGetingIndex = 0; //字段获取顺序的索引，如果有子查询，那么子查询使用父查询的该索引进行递增
		private SqlServerLock serverLock = SqlServerLock.UNKNOW;
		private bool disposed; //是否已经调用了Dispose方法

		protected internal int GetFieldGettingIndex()
		{
			if(parentCommand != null)
			{
				return parentCommand.GetFieldGettingIndex();
			}
			return ++fieldGetingIndex;
		}

		/// <summary>
		/// 是否具有子查询
		/// </summary>
		protected internal bool haveChildCommand = false;

		/// <summary>
		/// Where之后的Command字符串
		/// </summary>
		protected internal string CommandString = "";

		/// <summary>
		/// 字段堆栈
		/// </summary>
		protected internal Stack<TableNameField> fieldStack = new Stack<TableNameField>();

		//private Dictionary<string, TableNameField> dictParaNameField = new Dictionary<string, TableNameField>();
		/// <summary>
		/// SQL 函数
		/// </summary>
		protected internal string sqlFunctionString = string.Empty;

		/// <summary>
		/// 分组字段名
		/// </summary>
		protected internal List<string> GroupbyFieldNames
		{
			get
			{
				if(_groupbyFieldNames == null)
				{
					_groupbyFieldNames = new List<string>();
				}
				return _groupbyFieldNames;
			}
		}

		protected internal List<TableNameField> selectedFieldInfo = new List<TableNameField>();

		#endregion

		#region 旧方法

		private Dictionary<string, TableNameField> _parameters;

		/// <summary>
		/// 获取条件参数
		/// </summary>
		public Dictionary<string, TableNameField> Parameters
		{
			get
			{
				if(_parameters == null)
				{
					_parameters = new Dictionary<string, TableNameField>();
				}
				return _parameters;
			}
		}

		/// <summary>
		/// 实体类映射的类型
		/// </summary>
		public MappingType EntityMap
		{
			get;
			protected set;
		}

		/// <summary>
		/// 根据用户自定义的查询（临时视图），从该查询进一步获取指定的记录的查询语句
		/// </summary>
		/// <param name="tempViewSql">作为子表的用户查询（临时视图）</param>
		/// <returns>符合当前限定条件的查询语句</returns>
		public string GetMapSQL(string tempViewSql)
		{
			if(string.IsNullOrEmpty(tempViewSql))
			{
				throw new Exception("用户的子查询不能为空。");
			}
			this.mainTableName = " (" + tempViewSql + " ) tempView ";
			return ToSelectString("");
		}

		/// <summary>
		/// 要初始化的的参数值，用于自定义查询的实体类
		/// </summary>
		public Dictionary<string, object> InitParameters
		{
			get;
			set;
		}

		#endregion

		#region 新增非公开方法

		/// <summary>
		/// 获取Command使用的字段名
		/// </summary>
		/// <param name="tnf"></param>
		/// <returns></returns>
		protected internal string GetCommandFieldName(TableNameField tnf)
		{
			if(dictAliases == null)
			{
				return string.Format(" [{0}]", tnf.Field);
			}
			else
			{
				string aliases = "";
				if(dictAliases.TryGetValue(tnf.Entity, out aliases))
				{
					return string.Format(" {0}.[{1}]", aliases, tnf.Field); //关联查询，此处可能需要考虑字段AS别名 问题
				}
				else
				{
					return string.Format(" M.[{0}]", tnf.Field);
				}
			}
		}

		/// <summary>
		/// 获取表的别名
		/// </summary>
		/// <param name="entity"></param>
		/// <returns></returns>
		protected internal string GetTableAliases(IEntity entity)
		{
			string aliases = "";
			if(dictAliases.TryGetValue(entity, out aliases))
			{
				return aliases;
			}
			else
			{
				return "";
			}
		}

		/// <summary>
		/// 从堆栈上取一个以逗号间隔字段名数组字符串
		/// </summary>
		/// <returns></returns>
		protected internal string TakeStackFields()
		{
			string[] fieldNames = new string[fieldStack.Count];
			for(int i = fieldStack.Count - 1; i >= 0; i--)
			{
				TableNameField tnf = fieldStack.Pop();
				fieldNames[i] = GetCommandFieldName(tnf);
			}
			return string.Join(",", fieldNames);
		}

		private TableNameField TackOneParentStackField()
		{
			if(parentCommand == null)
			{
				throw new InvalidOperationException("Command的父对象为空！");
			}
			var tnf = parentCommand.TakeOneStackFields();
			string parentField = tnf.SqlFieldName;
			if(parentField.IndexOf('.') == -1)
			{
				tnf.SqlFieldName = "M." + parentField;
			}
			return tnf;
		}

		/// <summary>
		/// 从堆栈上只取一个字段名
		/// </summary>
		/// <returns></returns>
		protected internal TableNameField TakeOneStackFields()
		{
			if(fieldStack.Count == 0)
			{
				//如果父Command不为空，则从父对象获取字段堆栈
				if(parentCommand != null)
				{
					return TackOneParentStackField();
				}
				else
				{
					throw new ArgumentException("Command 字段堆栈为空！可能为方法参数未曾调用过Command关联的实体类的属性。");
				}
			}
			TableNameField tnf = fieldStack.Pop();
			tnf.SqlFieldName = GetCommandFieldName(tnf);
			return tnf;
		}

		/// <summary>
		/// 从堆栈上取一个字段
		/// </summary>
		/// <param name="index">使用的索引号</param>
		/// <returns></returns>
		//protected internal string TakeOneStackFields(out int index)
		//{
		//    if (fieldStack.Count == 0)
		//    {
		//        //如果父Command不为空，则从父对象获取字段堆栈
		//        if (parentCommand != null)
		//            return TackOneParentStackField(out index);
		//        else
		//            throw new ArgumentException("Command 字段堆栈为空！可能为方法参数未曾调用过Command关联的实体类的属性。");
		//    }
		//    TableNameField tnf = fieldStack.Pop();
		//    index = tnf.Index;
		//    return GetCommandFieldName(tnf);
		//}
		/// <summary>
		/// 尝试获取另一个堆栈中的字段，仅当堆栈中剩下一个的时候有效
		/// </summary>
		/// <returns></returns>
		//protected internal string TryTakeOneStackFields()
		//{
		//    if (fieldStack.Count == 1)
		//    {
		//        TableNameField tnf = fieldStack.Pop();
		//        return GetCommandFieldName(tnf);
		//    }
		//    else
		//    {
		//        if (parentCommand != null)
		//        {
		//            int index = 0;
		//            return TackOneParentStackField(out index);
		//        }
		//    }
		//    return "";
		//}
		/// <summary>
		/// 从堆栈上获取2个字段信息，可能只获取到一个字段信息并自动判断字段是左还是右
		/// </summary>
		/// <typeparam name="T">属性字段的类型</typeparam>
		/// <param name="leftParaValue">左边参数的值</param>
		/// <param name="rightParaValue">右边待比较参数的值</param>
		/// <param name="leftField">输出的左字段</param>
		/// <param name="rightField">输出的右字段</param>
		protected internal void TakeTwoStackFields<T>(T leftParaValue, object rightParaValue, out TableNameField leftField, out TableNameField rightField)
		{
			leftField = null;
			rightField = null;
			int count = fieldStack.Count;
			if(count == 0)
			{
				//在子查询中条件比较左右字段都用父查询的字段，是不合理的
				throw new ArgumentException("Command 字段堆栈为空！可能原因为方法使用的实体类不是Command使用的，或者未使用任何实体类属性，或者使用了父查询的Command的实体类属性。");
			}
			else if(count == 1)
			{
				TableNameField tnf = fieldStack.Pop();
				//string fieldName = GetCommandFieldName(tnf);
				tnf.SqlFieldName = GetCommandFieldName(tnf);
				//如果当前是子查询，还需要检查父查询的字段堆栈
				if(parentCommand != null)
				{
					var tnfParent = TackOneParentStackField();
					//int parentFieldIndex = tnfParent.Index;
					//string parentField = tnfParent.SqlFieldName;
					if(tnf.Index < tnfParent.Index)
					{
						leftField = tnf;
						rightField = tnfParent;
					}
					else
					{
						rightField = tnf;
						leftField = tnfParent;
					}
				}
				else
				{
					//通过获取的字段名关联的值，来确定参数所在的顺序
					/*
                     * //下面注释掉的代码 与后面的5 行代码等效 dth,2015.4.29
                    object Value = tnf.Entity.PropertyList(tnf.Field);
                    if (Value == DBNull.Value) Value = null;
                    if (Value != null)
                    {
                        //实体属性字段已经赋值过或者为string 类型
                        if (object.Equals(leftParaValue, Value))
                            leftField = tnf;
                        else
                            rightField = tnf;
                    }
                    else
                    {
                        //日期类型必须特殊处理，感谢网友 Sharp_C发现此问题
                        if (typeof(T) == typeof(DateTime) && object.Equals(leftParaValue, new DateTime(1900, 1, 1)))
                            leftField = tnf;
                        else if (object.Equals(default(T), leftParaValue))
                            leftField = tnf;
                        else
                            rightField = tnf;
                    }
                     */
					//
					T Value = Utility.ConvertType<T>(tnf.Entity.GetPropertyValue(tnf.Field));
					if(object.Equals(leftParaValue, Value))
					{
						leftField = tnf;
					}
					else if(object.Equals(rightParaValue, Value)) //增加对右边参数值的判断 2015.5.11
					{
						rightField = tnf;
					}
					else
					{
						leftField = tnf;
					}
				}
			}
			else if(count >= 2)
			{
				//必定是连接查询，左右参数都是字段，而不是值
				TableNameField tnf1 = fieldStack.Pop();
				string fieldName1 = GetCommandFieldName(tnf1);
				tnf1.SqlFieldName = fieldName1;
				//正常情况应该是 tnf1.Index > tnf2.Index
				//tnf1的值如果不是CommandCompare.Comparer方法比较类别右边参数的值（即第三个参数），那么tnf1必定是左边参数的值，参照下面这这样的情况：
				/* //cmp 为 CommandCompare 对象
                 * CommandCompare cmpResult=null; 
                 * if(user.City=="bei jing")
                 *   cmpResult =cmp.Comparer(user.Address,"like","chao yang %");
                 * 
                 * //上面2行代码并不安全，假如 user.Address=="chao yang %" ，框架无法确定user.Address 是方法上面的第一个调用参数，因为之前有
                 * //user.City=="bei jing" 调用，对实体类属性获取了值，这样在Command字段堆栈上，将有 2个元素，而不是1个。正常情况下，字段堆栈首先弹出
                 * // 的字段 ，也就是属性 user.Address,它会跟 Comparer 方法的第三个参数的值进行比较，如果不一致，则可以确定 user.Address 
                 * // 是在第一个参数上调用的，否则就可能是在第三个参数上调用的，然后把 user.City 从Command字段堆栈上弹出来，作为 Comparer 方法的第一个参数，
                 * // 从而构造这样错误的条件：
                 *      "[City] like  [Address]"
                 * //当然，如果能够确信 Comparer 方法的第一个参数与第三个参数值不会相等，那么上面的代码可以放心的使用。如果不能确信，那么最好将
                 * //代码改写成：
                 * if(user.City=="bei jing")
                 *   cmpResult =cmp.NewCompare().Comparer(user.Address,"like","chao yang %");
                 *   
                 * //或者改写成下面这样：
                 * if(user.City=="bei jing")
                 *   cmpResult =cmp.Comparer(user.Address,"like","chao yang %");
                 * else
                 *   cmp.NewCompare();
                 *   
                 * //其它情况，如果在构造比较条件之前，要对“同一个实体类属性”进行检查之类，那么是不会有上面问题的担心的，比如下面的代码：
                 * string userName=user.Name;
                 * if(string.IsNullOrEmpty(userName))
                 *    cmpResult =cmp.Comparer(user.Name,"=",userName);
                 *    //如果是相等比较，推荐用这种方式实现上面的比较： cmpResult =cmp.EqualValue(userName);
                 */
				T Value = Utility.ConvertType<T>(tnf1.Entity.GetPropertyValue(tnf1.Field));
				if(object.Equals(Value, leftParaValue) && !object.Equals(Value, rightParaValue))
				{
					//修改 2015.7.5
					//如果 T 是 int 等基础类型，下面代码无法创建泛型类型，注释 
					//Type genericTypeDefinition = typeof(T).GetGenericTypeDefinition();
					//if (genericTypeDefinition == typeof(Nullable<>))
					//{
					//    throw new ArgumentException("当前情况下 Comparer 方法调用的参数有可空类型于非可空类型的属性进行比较，无法推断参数调用顺序！");
					//}
					leftField = tnf1;
				}
				else
				{
					/* //示例：假设cmp对象是一个 CommandCompare对象，user是一个实体类，看下面的代码：
                     * if(user.Age > 20)
                     *    cmpResult =cmp.Comparer(user.Name,"<>","");
                     *    
                     * //如果用户名恰好等于空字符串，那么这个比较条件可能生成下面的查询：
                     *   " Name <> Age "
                     * //显然这是不正确的，应该避免这种第一个参数和第三个参数相等，可行的办法就是给 user.Name 赋予一个不同的值，或者调用 cmp.NewCompare() 方法
                     * //参见上面的说明
                     */
					TableNameField tnf2 = fieldStack.Pop();
					string fieldName2 = GetCommandFieldName(tnf2);
					tnf2.SqlFieldName = fieldName2;
					leftField = tnf2;
					rightField = tnf1;
				}
				fieldStack.Clear();
			}
			else
			{
				throw new InvalidOperationException("当前Command对象的字段堆栈出现了未期望的字段数量：" + count);
			}
		}

		/// <summary>
		/// 使用当前参数值，创建一个参数名，并将参数的值放到当前对象的参数字典中去
		/// </summary>
		/// <param name="Value"></param>
		/// <returns></returns>
		protected internal string CreateParameter(TableNameField Value)
		{
			string paraName = "@P" + paraIndex++;
			Parameters.Add(paraName, Value);
			return paraName;
		}

		protected internal string CreateParameter(TableNameField field, object Value)
		{
			TableNameField tnf = new TableNameField();
			if(field != null)
			{
				tnf.Entity = field.Entity;
				tnf.Field = field.Field;
				tnf.Index = field.Index;
				tnf.SqlFieldName = field.SqlFieldName;
			}
			tnf.FieldValue = Value;
			return CreateParameter(tnf);
		}

		/// <summary>
		/// 获取当前Command对象正在使用的实体类
		/// </summary>
		/// <typeparam name="T"></typeparam>
		/// <returns></returns>
		protected internal T GetUsedEntity<T>() where T : class
		{
			if(this.currEntity is T)
			{
				return this.currEntity as T;
			}
			if(dictAliases != null)
			{
				foreach(object key in dictAliases.Keys)
				{
					if(key is T)
					{
						return key as T;
					}
				}
			}
			return null;
		}

		/// <summary>
		/// 获取当前Command使用的所有实体类
		/// </summary>
		/// <returns></returns>
		protected internal IEntity[] GetAllUsedEntity()
		{
			List<IEntity> list = new List<IEntity>();
			list.Add(this.currEntity);
			if(dictAliases != null)
			{
				foreach(object key in dictAliases.Keys)
				{
					list.Add(key as IEntity);
				}
			}
			return list.ToArray();
		}

		private void e_PropertyGetting(object sender, PropertyGettingEventArgs e)
		{
			TableNameField tnf = new TableNameField()
			{
				Field = e.PropertyName, Entity = (IEntity)sender, Index = this.GetFieldGettingIndex()
			};
			//tnf.FieldValue = tnf.Entity.PropertyList(tnf.Field);
			fieldStack.Push(tnf);
		}

		private JoinEntity Join(IEntity entity, string joinTypeString)
		{
			if(dictAliases == null)
			{
				dictAliases = new Dictionary<object, string>();
			}
			dictAliases.Add(entity, "T" + dictAliases.Count);
			haveJoinOpt = true;
			entity.PropertyGetting += new EventHandler<PropertyGettingEventArgs>(e_PropertyGetting);
			JoinEntity je = new JoinEntity(this, entity, joinTypeString);
			return je;
		}

		#endregion

		#region Command CRUD 方法

		/// <summary>
		/// 选取要调用的实体类属性字段。该方法可以在Command实例对象上多次调用
		/// </summary>
		/// <param name="fields"></param>
		/// <returns></returns>
		public Command1 Select(params object[] fields)
		{
			if(disposed)
			{
				throw new Exception("当前Command对象已经执行过数据查询，不能再次调用本方法。在执行查询前是可以再次调用本方法的。");
			}
			//防止在调用本方法之前访问关联的实体类属性带来的问题。
			//感谢网友 GIV-顺德 发现此问题
			if(fields.Length > 0)
			{
				int count = fieldStack.Count;
				if(count > fields.Length) //防止才执行本方法前访问了实体类的属性
				{
					count = fields.Length;
				}
				for(int i = 0; i < count; i++)
				{
					TableNameField tnf = fieldStack.Pop();
					selectedFieldNames.Add(string.Format("\r\n    {0}", GetCommandFieldName(tnf)));
					selectedFieldInfo.Add(tnf);
				}
			}
			fieldStack.Clear();
			selectedFieldNames.Reverse(); //恢复正常的字段选取顺序
			selectedFieldInfo.Reverse();
			return new Command1(this);
		}

		/// <summary>
		/// 使用是否排除重复记录的方式，来选取实体对象的属性
		/// <remarks>2014.1.6  网友※DS 调用本方法的时候，发现调用的第一个实体类属性是bool类型，
		/// 引起少了一个字段查询的问题 </remarks>
		/// </summary>
		/// <param name="distinct"></param>
		/// <param name="fields"></param>
		/// <returns></returns>
		public Command1 Select(bool distinct, params object[] fields)
		{
			int count = fieldStack.Count;
			if(count == fields.Length + 1)
			{
				object[] newFields = new object[count];
				for(int i = 1; i < count; i++)
				{
					newFields[i] = fields[i - 1];
				}
				newFields[0] = false;
				return Select(newFields);
			}
			this.Distinct = distinct;
			return Select(fields);
		}

		/// <summary>
		/// 直接将结果映射到POCO对象,待实现
		/// </summary>
		/// <typeparam name="TResult"></typeparam>
		/// <param name="q"></param>
		/// <param name="mapAction"></param>
		/// <returns></returns>
		//public IList<TResult> MapToList<TResult>(Func<TResult,TResult> mapFun) where TResult : class
		//{
		//    mapAction();
		//    return null;
		//}
		private string PreUpdate()
		{
			string sqlUpdate = "UPDATE " + mainTableName + " SET ";
			string[] updateFieldsString = new string[selectedFieldNames.Count];
			//先将Where条件的参数保存起来
			Dictionary<string, TableNameField> paraTemp = new Dictionary<string, TableNameField>();
			foreach(string key in this.Parameters.Keys)
			{
				paraTemp.Add(key, this.Parameters[key]);
			}
			this.Parameters.Clear();
			//
			for(int i = 0; i < selectedFieldNames.Count; i++)
			{
				int a = selectedFieldNames[i].IndexOf('[');
				int b = selectedFieldNames[i].IndexOf(']');
				string realField = selectedFieldNames[i].Substring(a + 1, b - a - 1);
				updateFieldsString[i] = selectedFieldNames[i];
				object Value = currEntity.GetPropertyValue(realField);
				TableNameField tnf = new TableNameField();
				tnf.Entity = this.currEntity;
				tnf.Field = realField;
				tnf.FieldValue = Value;
				tnf.Index = i;
				string paraName = CreateParameter(tnf); //参数应该在Ｗｈｅｒｅ的参数前面
				updateFieldsString[i] += " = " + paraName;
			}
			sqlUpdate += string.Join(",", updateFieldsString);
			//恢复条件参数
			foreach(string key in paraTemp.Keys)
			{
				this.Parameters.Add(key, paraTemp[key]);
			}
			return sqlUpdate;
		}

		private string PreUpdateSelf()
		{
			string sqlUpdate = "UPDATE " + mainTableName + " SET ";
			string[] updateFieldsString = new string[selectedFieldNames.Count];
			for(int i = 0; i < selectedFieldNames.Count; i++)
			{
				int a = selectedFieldNames[i].IndexOf('[');
				int b = selectedFieldNames[i].IndexOf(']');
				string realField = selectedFieldNames[i].Substring(a + 1, b - a - 1);
				object Value = currEntity.GetPropertyValue(realField);
				TableNameField tnf = new TableNameField();
				tnf.Entity = this.currEntity;
				tnf.Field = realField;
				tnf.FieldValue = Value;
				tnf.Index = i;
				string paraName = CreateParameter(tnf);
				updateFieldsString[i] = string.Format(" {0} = {1} {2} {3} ", selectedFieldNames[i], selectedFieldNames[i], this.updateSelfOptChar, paraName);
			}
			sqlUpdate += string.Join(",", updateFieldsString);
			return sqlUpdate;
		}

		/// <summary>
		/// 更新实体类的某些属性值，如果未指定条件，则使用主键值为条件。
		/// </summary>
		/// <param name="fields">实体熟悉列表</param>
		/// <returns>条件表达式</returns>
		public Command1 Update(params object[] fields)
		{
			if(fields.Length == 0)
			{
				throw new ArgumentException("Command Update 操作必须指定要操作的实体类的属性！");
			}
			optFlag = Command_UPDATE;
			Command1 q1 = Select(fields);
			this.sql_from = PreUpdate();
			return q1;
		}

		/// <summary>
		/// 执行自操作的字段更新，比如为某一个数值性字段执行累加
		/// </summary>
		/// <param name="selfOptChar">自操作类型，有+，-，*，/ 四种类型</param>
		/// <param name="fields">字段列表</param>
		/// <returns></returns>
		public Command1 UpdateSelf(char selfOptChar, params object[] fields)
		{
			if(selfOptChar == '+' || selfOptChar == '-' || selfOptChar == '*' || selfOptChar == '/')
			{
				optFlag = Command_UPDATE_SELFT;
				updateSelfOptChar = selfOptChar;
				var q1 = Select(fields);
				this.sql_from = PreUpdateSelf();
				return q1;
			}
			throw new Exception("Command的字段自操作只能是+，-，*，/ 四种类型");
		}

		public Command Insert(params object[] fields)
		{
			if(fields.Length == 0)
			{
				throw new ArgumentException("Command Insert 操作必须指定要操作的实体类的属性！");
			}
			optFlag = Command_INSERT;
			Select(fields);
			return this;
		}

		public Command InsertFrom(Command childCommand, params object[] targetTableFields)
		{
			if(targetTableFields.Length == 0)
			{
				throw new ArgumentException("Command Insert 操作必须指定要操作的实体类的属性！");
			}
			optFlag = Command_INSERT_FROM;
			Select(targetTableFields);
			insertFromCommand = childCommand;
			return this;
		}

		/// <summary>
		/// 删除实体类，如果未指定条件，则使用主键值为条件。
		/// </summary>
		/// <returns>条件表达式</returns>
		public Command1 Delete()
		{
			optFlag = Command_DELETE;
			return new Command1(this);
		}

		#endregion

		#region 构造或者获取实例相关

		public Command End()
		{
			return this;
		}

		public Command(IEntity e)
		{
			currEntity = e;
			mainTableName = e.GetSchemeTableName();
			sql_table = mainTableName;
			EntityMap = e.GetMappingType();
			e.PropertyGetting += new EventHandler<PropertyGettingEventArgs>(e_PropertyGetting);
		}

		public Command(IEntity e, params IEntity[] others) : this(e)
		{
			if(dictAliases == null)
			{
				dictAliases = new Dictionary<object, string>();
			}
			foreach(IEntity entity in others)
			{
				string aliases = "T" + dictAliases.Count;
				dictAliases.Add(entity, aliases);
				entity.PropertyGetting += new EventHandler<PropertyGettingEventArgs>(e_PropertyGetting);
				CommandString += string.Format(",{0} {1}", entity.GetSchemeTableName(), aliases);
			}
		}

		protected internal void AddOtherEntitys(params IEntity[] others)
		{
			if(dictAliases == null)
			{
				dictAliases = new Dictionary<object, string>();
			}
			foreach(IEntity entity in others)
			{
				string aliases = "T" + dictAliases.Count;
				dictAliases.Add(entity, aliases);
				entity.PropertyGetting += new EventHandler<PropertyGettingEventArgs>(e_PropertyGetting);
			}
		}

		public Command(Command parent, IEntity e) : this(e)
		{
			parentCommand = parent;
			parent.haveChildCommand = true;
		}

		/// <summary>
		/// 以一个实体类实例对象初始化Command对象。
		/// </summary>
		/// <param name="e"></param>
		/// <returns></returns>
		public static Command From(IEntity e)
		{
			return new Command(e);
		}

		public static Command From(IEntity e, params IEntity[] others)
		{
			return new Command(e, others);
		}

		public static Command From(Command parent, IEntity e)
		{
			return new Command(parent, e);
		}

		/// <summary>
		/// 根据接口类型，返回查询数据的泛型Command表达式
		/// <example>
		/// <code>
		/// <![CDATA[
		///   List<User> users=Command.From<User>.ToList();
		/// ]]>
		/// </code>
		/// </example>
		/// </summary>
		/// <typeparam name="T">实体类类型</typeparam>
		/// <returns>Command表达式</returns>
		public static Command<T> FromObject<T>() where T : class, IEntity, new()
		{
			T obj = EntityBuilder.CreateEntity<T>();
			IEntity eb = obj as IEntity;
			if(eb == null)
			{
				throw new ArgumentException("类型的实例必须是继承IEntity的子类！");
			}
			Command q = Command.From(eb);
			return new Command<T>(q, obj);
		}

		/// <summary>
		/// 根据实体类类型，返回查询数据的泛型Command表达式
		/// <remarks>2015.2.15 修改成返回GCommand的方式，避免之前可能的误用</remarks>
		/// <example>
		/// <code>
		/// <![CDATA[
		///   List<User> users=Command.From<User>.ToList<User>();
		/// ]]>
		/// </code>
		/// </example>
		/// </summary>
		/// <typeparam name="T">实体类类型</typeparam>
		/// <returns>Command表达式</returns>
		public static Command<T> From<T>() where T : class, IEntity, new()
		{
			T entity = new T();
			Command q = new Command(entity);
			return new Command<T>(q, entity);
		}

		#endregion

		#region 连接查询

		/// <summary>
		/// 内连接查询
		/// </summary>
		/// <param name="e">要连接的实体对象</param>
		/// <returns>连接对象</returns>
		public JoinEntity Join(IEntity e)
		{
			return Join(e, "INNER JOIN");
		}

		/// <summary>
		/// 内连接查询
		/// </summary>
		/// <param name="e">要连接的实体对象</param>
		/// <returns>连接对象</returns>
		public JoinEntity InnerJoin(IEntity e)
		{
			return Join(e, "INNER JOIN");
		}

		/// <summary>
		/// 左连接查询
		/// </summary>
		/// <param name="e">要连接的实体对象</param>
		/// <returns>连接对象</returns>
		public JoinEntity LeftJoin(IEntity e)
		{
			return Join(e, "LEFT JOIN");
		}

		/// <summary>
		/// 右连接查询
		/// </summary>
		/// <param name="e">要连接的实体对象</param>
		/// <returns>连接对象</returns>
		public JoinEntity RightJoin(IEntity e)
		{
			return Join(e, "RIGHT JOIN");
		}

		#endregion

		#region 获取查询字符串 辅助内部方法

		private string ToInsertFromString(string sql)
		{
			Parameters.Clear();
			string sqlTemplate = "INSERT INTO {0}({1}\r\n\t) \r\n{2} ";
			int count = selectedFieldNames.Count;
			string[] insertFieldsString = new string[count];
			for(int i = 0; i < count; i++)
			{
				int a = selectedFieldNames[i].IndexOf('[');
				int b = selectedFieldNames[i].IndexOf(']');
				string realField = selectedFieldNames[i].Substring(a + 1, b - a - 1);
				insertFieldsString[i] = selectedFieldNames[i];
			}
			sql = string.Format(sqlTemplate, mainTableName, string.Join(",", insertFieldsString), insertFromCommand);
			foreach(string key in insertFromCommand.Parameters.Keys)
			{
				Parameters.Add(key, insertFromCommand.Parameters[key]);
			}
			return sql;
		}

		private string ToInsertString(string sql)
		{
			Parameters.Clear();
			string sqlTemplate = "INSERT INTO {0}({1}) \r\nVALUES\r\n    ({2}) ";
			int count = selectedFieldNames.Count;
			string[] insertFieldsString = new string[count];
			string[] valuesString = new string[count];
			for(int i = 0; i < count; i++)
			{
				int a = selectedFieldNames[i].IndexOf('[');
				int b = selectedFieldNames[i].IndexOf(']');
				string realField = selectedFieldNames[i].Substring(a + 1, b - a - 1);
				insertFieldsString[i] = selectedFieldNames[i];
				object Value = currEntity.GetPropertyValue(realField);
				TableNameField tnf = new TableNameField();
				tnf.Entity = this.currEntity;
				tnf.Field = realField;
				string paraName = CreateParameter(tnf, Value);
				valuesString[i] = paraName;
			}
			sql = string.Format(sqlTemplate, mainTableName, string.Join(",", insertFieldsString), string.Join(",", valuesString));
			return sql;
		}

		private string ToUpdateString(string sql)
		{
			//if (selectedFieldNames.Count == 0)
			//    throw new ArgumentException("UPDATE 操作未指定任何要更新的字段！");
			sql = this.sql_from + GetWhereString();
			return sql;
		}

		private string ToSelectString(string sql)
		{
			string sqlVar = "";
			if(this.Distinct)
			{
				sqlVar += " DISTINCT ";
			}
			if(TopCount > 0)
			{
				sqlVar += " TOP " + TopCount + " "; //仅限于SQLSERVER/ACCESS
			}

			#region 校验GROUP BY 子句

			string sqlFunTemp = string.Empty;
			if(sqlFunctionString.Length > 0) //是否有聚合函数
			{
				sqlFunTemp = sqlFunctionString;
				if(selectedFieldNames.Count > 0)
				{
					//GROUP BY 
					if(GroupbyFieldNames.Count == 0)
					{
						throw new FormatException("在SELECT 子句中使用聚合、统计函数，如果同时选取了查询的列，那么SQL必须使用GROUP BY 子句！");
					}
					sqlFunTemp = "," + sqlFunTemp;
				}
			}
			else
			{
				//没有聚合函数，也得检查选择的字段是否在分组的字段内
				int count = GroupbyFieldNames.Count;
				if(count > 0)
				{
					if(selectedFieldNames.Count == 0)
					{
						throw new FormatException("如果使用GROUP BY 子句，那么在SELECT 子句中中必须指明要选取的列！");
					}
					foreach(string str in selectedFieldNames)
					{
						string item = str.Trim();
						if(!GroupbyFieldNames.Contains(item))
						{
							throw new FormatException("如果使用GROUP BY 子句，那么在SELECT 子句中查询的列必须也在GROUP BY 子句中出现！错误的列：" + item);
						}
					}
				}
			}

			#endregion

			sql_fields = string.Join(",", selectedFieldNames.ToArray());
			if(dictAliases != null) //有关联查询
			{
				sql_from = mainTableName + " M ";
				if(sql_fields == "" && sqlFunctionString.Length == 0)
				{
					if(SelectStar)
					{
						sql_fields = "*"; //网友 大大宝 增加该分支
					}
					else
					{
						sql_fields = "M.*";
						foreach(string str in dictAliases.Values)
						{
							sql_fields += string.Format(",{0}.*", str);
						}
					}
				}
			}
			else
			{
				sql_from = mainTableName;
				if(sql_fields == "" && sqlFunctionString.Length == 0)
				{
					if(SelectStar)
					{
						sql_fields = "*";
					}
					else
					{
						sql_fields = "[" + string.Join("],[", this.currEntity.GetPropertyNames()) + "]"; // "*";
					}
				}
				if(haveChildCommand)
				{
					sql_from = mainTableName + " M ";
				}
			}
			sql = string.Format("SELECT {0} {1} {2} \r\nFROM {3} {4} {5} ", sqlVar, sql_fields, sqlFunTemp, sql_from, serverLock == SqlServerLock.UNKNOW ? "" : "WITH(" + serverLock.ToString() + ") ", CommandString);
			if(this.PageEnable)
			{
				if(this.PageField == "" && sql.IndexOf(" order by ", StringComparison.OrdinalIgnoreCase) <= 0)
				{
					if(this.currEntity.GetPrimaryKey() == null || this.currEntity.GetPrimaryKey().Count == 0)
					{
						throw new Exception("Command 分页错误，没有指明分页标识字段，也未给当前实体类设置主键。");
					}
					this.PageField = this.currEntity.GetPrimaryKey()[0];
				}
			}
			return sql;
		}

		/// <summary>
		/// 获取条件字符串，如果未限定条件，则使用主键的值
		/// </summary>
		/// <returns></returns>
		private string GetWhereString()
		{
			string whereString = CommandString;
			if(whereString.Length < 8)
			{
				whereString = " Where 1=1 ";
				if(this.currEntity.GetPrimaryKey().Count == 0)
				{
					throw new Exception("未指定操作实体的范围，也未指定实体的主键。");
				}
				foreach(string pk in this.currEntity.GetPrimaryKey())
				{
					TableNameField tnf = new TableNameField();
					tnf.Entity = this.currEntity;
					tnf.Field = pk;
					string paraName = CreateParameter(tnf, currEntity.GetPropertyValue(pk));
					whereString += " And [" + pk + "] =" + paraName + ",";
				}
				whereString = whereString.TrimEnd(',');
				//去除下一次生成重复的条件
				CommandString = whereString;
			}
			return whereString;
		}

		#endregion

		#region 其它方法

		private Filter _filter;

		/// <summary>
		/// 获取当前条件比较对象
		/// </summary>
		public Filter Filter
		{
			get
			{
				if(_filter == null)
				{
					_filter = new Filter(this);
				}
				return _filter;
			}
		}

		public override string ToString()
		{
			string sql = string.Empty;
			if(optFlag == Command_SELECT)
			{
				sql = ToSelectString(sql);
			}
			else if(optFlag == Command_UPDATE || optFlag == Command_UPDATE_SELFT)
			{
				sql = ToUpdateString(sql);
			}
			else if(optFlag == Command_DELETE)
			{
				string sqlUpdate = "DELETE FROM " + mainTableName + " ";
				sql = sqlUpdate + GetWhereString();
			}
			else if(optFlag == Command_INSERT)
			{
				sql = ToInsertString(sql);
			}
			else if(optFlag == Command_INSERT_FROM)
			{
				sql = ToInsertFromString(sql);
			}
			return sql;
		}

		public string PrintParameterInfo()
		{
			if(Parameters == null || Parameters.Count == 0)
			{
				return "-------No paramter.--------\r\n";
			}
			StringBuilder sb = new StringBuilder();
			foreach(var item in Parameters)
			{
				object fieldValue = item.Value.FieldValue;
				string type = fieldValue == null ? "NULL" : fieldValue.GetType().Name;
				sb.Append(string.Format("  {0}={1} \t Type:{2} \r\n", item.Key, fieldValue, type));
			}
			string paraInfoString = string.Format("--------Command Parameters information----------\r\n have {0} parameter,detail:\r\n{1}", Parameters.Count, sb);
			return paraInfoString + "------------------End------------------------\r\n";
		}

		/// <summary>
		/// 释放实体类事件挂钩。如果没页手工调用，该方法会在DataAccess 调用
		/// </summary>
		public void Dispose()
		{
			if(disposed)
			{
				return;
			}
			this.currEntity.PropertyGetting -= new EventHandler<PropertyGettingEventArgs>(e_PropertyGetting);
			if(this.dictAliases != null)
			{
				foreach(IEntity item in dictAliases.Keys)
				{
					item.PropertyGetting -= new EventHandler<PropertyGettingEventArgs>(e_PropertyGetting);
				}
			}
			disposed = true;
		}

		/// <summary>
		/// 如果未选择任何列，生成的SQL语句Select 后面是否用 * 代替。
		/// 用于不想修改实体类结构但又想增加表字段的情况。
		/// </summary>
		public bool SelectStar
		{
			get;
			set;
		}

		/// <summary>
		/// 制定实体查询的时候表的锁定类型。仅支持SqlServer。
		/// </summary>
		/// <param name="lockType"></param>
		/// <returns></returns>
		public Command With(SqlServerLock lockType)
		{
			serverLock = lockType;
			return this;
		}

		public Command With(string sqlLockType)
		{
			sqlLockType = sqlLockType.ToUpper();
			try
			{
				SqlServerLock lockType = (SqlServerLock)Enum.Parse(typeof(SqlServerLock), sqlLockType);
				serverLock = lockType;
				return this;
			}
			catch(Exception ex)
			{
				throw new ArgumentException(sqlLockType + " 不是SQLSERVER 要求的锁定类型！请参见SqlServerLock 枚举定义。");
			}
		}

		/// <summary>
		/// 获取关联的实体类的表名字，如果是关联查询，返回空
		/// </summary>
		/// <returns></returns>
		protected internal string GetEntityTableName()
		{
			if(this.haveChildCommand || this.haveJoinOpt)
			{
				return "";
			}
			else
			{
				return this.currEntity.GetMappingName();
			}
		}

		#endregion
	}

	public class Command1 : Command4, ICommand1
	{
		private Command CurrentCommand;

		private string GetWhereFields()
		{
			int count = CurrentCommand.fieldStack.Count;
			TableNameField[] tnfs = new TableNameField[count];
			for(int i = count - 1; i >= 0; i--)
			{
				tnfs[i] = CurrentCommand.fieldStack.Pop();
			}
			string[] fieldNames = new string[count];
			for(int i = 0; i < count; i++)
			{
				TableNameField tnf = tnfs[i];
				string sqlField = CurrentCommand.GetCommandFieldName(tnf);
				tnf.SqlFieldName = sqlField;
				string paraName = CurrentCommand.CreateParameter(tnf, tnf.Entity.GetPropertyValue(tnf.Field));
				fieldNames[i] = string.Format("{0}={1}", sqlField, paraName);
			}
			return string.Join(" AND ", fieldNames);
		}

		public Command1(Command command) : base(command)
		{
			CurrentCommand = command;
		}

		public Command2 Where(Filter filter)
		{
			CurrentCommand.sql_condition = filter.WhereString;
			CurrentCommand.CommandString += "\r\n     WHERE " + CurrentCommand.sql_condition;
			return new Command2(CurrentCommand);
		}

		/// <summary>
		/// 根据传入的查询参数数组，对字段名执行不区分大小写的比较，生成查询条件。
		/// 注意目前要求QueryParameter 用的是要查询的表的字段名称，而不是实体类的属性名称
		/// </summary>
		/// <param name="queryParas">查询参数数组</param>
		/// <returns>条件表达式</returns>
		public Command2 Where(QueryParameter[] queryParas)
		{
			Dictionary<string, TableNameField> paras = CurrentCommand.Parameters;
			string[] fields = CurrentCommand.currEntity.GetPropertyNames();
			string str = "";
			int count = 0;
			foreach(QueryParameter para in queryParas)
			{
				foreach(string temp in fields) //比较字段是否在实体类中
				{
					if(string.Compare(temp, para.FieldName, true) == 0)
					{
						string paraName = temp + (count++);
						if(!paras.ContainsKey(paraName))
						{
							paras.Add(paraName, new TableNameField()
							{
								FieldValue = para.FieldValue, Field = para.FieldName, Entity = CurrentCommand.currEntity //必须指定，网友[长得没礼貌]发现此问题
							});
							string cmpType = "";
							switch(para.CompareType)
							{
								case Operator.Equal:
									cmpType = "=";
									break;
								case Operator.Greater:
									cmpType = ">";
									break;
								case Operator.Like:
									cmpType = " LIKE ";
									break;
								case Operator.NoGreater:
									cmpType = "<=";
									break;
								case Operator.NoSmaller:
									cmpType = ">=";
									break;
								case Operator.NotEqual:
									cmpType = "<>";
									break;
								case Operator.Smaller:
									cmpType = "<";
									break;
								case Operator.IsNull:
									cmpType = " IS NULL ";
									break;
								case Operator.IsNotNull:
									cmpType = " IS NOT NULL ";
									break;
								default:
									cmpType = "=";
									break;
							}
							if(para.CompareType != Operator.IsNull && para.CompareType != Operator.IsNotNull)
							{
								str += " AND [" + temp + "]" + cmpType + "@" + paraName;
							}
							else
							{
								str += " AND [" + temp + "]" + cmpType;
							}
						}
						break;
					}
				}
			}
			if(str != "")
			{
				str = str.Substring(" AND ".Length);
			}
			CurrentCommand.sql_condition = str;
			CurrentCommand.CommandString += "\r\n     WHERE " + CurrentCommand.sql_condition;
			return new Command2(CurrentCommand);
		}

		public Command2 Where(Comparer cmpResult)
		{
			return GetCommand2ByCommandCompare(cmpResult);
		}

		public Command2 Where(CompareFunc cmpFun)
		{
			Comparer compare = new Comparer(this.CurrentCommand);
			Comparer cmpResult = cmpFun(compare);
			return GetCommand2ByCommandCompare(cmpResult);
		}

		public Command2 Where<T>(CompareFunc<T> cmpFun) where T : class, IEntity, new()
		{
			Comparer compare = new Comparer(this.CurrentCommand);
			T p1 = GetInstance<T>();
			Comparer cmpResult = cmpFun(compare, p1);
			return GetCommand2ByCommandCompare(cmpResult);
		}

		public Command2 Where<T1, T2>(CompareFunc<T1, T2> cmpFun) where T1 : class, IEntity, new() where T2 : class, IEntity, new()
		{
			Comparer compare = new Comparer(this.CurrentCommand);
			T1 p1 = GetInstance<T1>();
			T2 p2 = GetInstance<T2>();
			Comparer cmpResult = cmpFun(compare, p1, p2);
			return GetCommand2ByCommandCompare(cmpResult);
		}

		public Command2 Where<T1, T2, T3>(CompareFunc<T1, T2, T3> cmpFun) where T1 : class, IEntity, new() where T2 : class, IEntity, new() where T3 : class, IEntity, new()
		{
			Comparer compare = new Comparer(this.CurrentCommand);
			T1 p1 = GetInstance<T1>();
			T2 p2 = GetInstance<T2>();
			T3 p3 = GetInstance<T3>();
			Comparer cmpResult = cmpFun(compare, p1, p2, p3);
			return GetCommand2ByCommandCompare(cmpResult);
		}

		private Command2 GetCommand2ByCommandCompare(Comparer cmpResult)
		{
			if(!object.Equals(cmpResult, null))
			{
				if(CurrentCommand != cmpResult.Command)
				{
					throw new ArgumentException("CommandCompare 关联的Command 对象不是当前Command本身对象，请使用CommandCompareFunc或者它的泛型对象。");
				}
				CurrentCommand.sql_condition = cmpResult.WhereString;
				CurrentCommand.CommandString += "\r\n     WHERE " + CurrentCommand.sql_condition;
			}
			return new Command2(CurrentCommand);
		}

		private T GetInstance<T>() where T : class, IEntity, new()
		{
			T entity = this.CurrentCommand.GetUsedEntity<T>();
			if(entity == null)
			{
				throw new ArgumentException(typeof(T).ToString() + " 类型的实例没有被Command对象所使用");
			}
			return entity;
		}

		#region 接口方法

		/// <summary>
		/// 使用实体类选定的属性作为查询条件和条件的值，必须有至少一个参数。该方法不可以多次调用。
		/// 如果想构造动态的查询条件，请使用CommandCompare 对象
		/// </summary>
		/// <param name="fields"></param>
		/// <returns></returns>
		public Command2 Where(params object[] fields)
		{
			CurrentCommand.sql_condition = GetWhereFields();
			CurrentCommand.CommandString += "\r\n     WHERE " + CurrentCommand.sql_condition;
			return new Command2(CurrentCommand);
		}

		public Command3 GroupBy(object field)
		{
			string fieldName = CurrentCommand.TakeOneStackFields().SqlFieldName;
			CurrentCommand.GroupbyFieldNames.Add(fieldName.Trim());
			CurrentCommand.CommandString += "\r\n          GROUP BY " + fieldName;
			return new Command3(CurrentCommand);
		}

		public Command3 GroupBy(object field, params object[] others)
		{
			string strTemp = string.Empty;
			string fieldName = CurrentCommand.TakeOneStackFields().SqlFieldName;
			CurrentCommand.GroupbyFieldNames.Add(fieldName.Trim());
			for(int i = 0; i < others.Length; i++)
			{
				string fieldNameTemp = CurrentCommand.TakeOneStackFields().SqlFieldName;
				CurrentCommand.GroupbyFieldNames.Add(fieldNameTemp.Trim());
				strTemp += "," + fieldNameTemp;
			}
			CurrentCommand.CommandString += "\r\n          GROUP BY " + fieldName + strTemp;
			return new Command3(CurrentCommand);
		}

		public Command4 Having(object field, object Value, string sqlFunctionFormat)
		{
			Command3 q3 = new Command3(CurrentCommand);
			return q3.Having(field, Value, sqlFunctionFormat);
		}

		#endregion

		#region 聚合函数

		/// <summary>
		/// Command1表达式之统计数量，请在结果实体类中使用PropertyList["字段别名"] 的方式获取查询值
		/// </summary>
		/// <param name="field">属性字段</param>
		/// <param name="asFieldName">别名，如果不指定，则使用字段名称</param>
		/// <returns>Command1</returns>
		public Command1 Count(object field, string asFieldName)
		{
			string currFieldName = CurrentCommand.TakeStackFields();
			if(string.IsNullOrEmpty(currFieldName))
			{
				currFieldName = "*";
			}
			return sqlFunction("COUNT", currFieldName, asFieldName);
		}

		/// <summary>
		/// Command1表达式之求最大值，请在结果实体类中使用PropertyList["字段别名"] 的方式获取查询值
		/// </summary>
		/// <param name="field">属性字段</param>
		/// <param name="asFieldName">别名，如果不指定，则使用字段名称</param>
		/// <returns>Command1</returns>
		public Command1 Max(object field, string asFieldName)
		{
			string currFieldName = CurrentCommand.TakeStackFields();
			return sqlFunction("MAX", currFieldName, asFieldName);
		}

		/// <summary>
		/// Command1表达式之求最小值，请在结果实体类中使用PropertyList["字段别名"] 的方式获取查询值
		/// </summary>
		/// <param name="field">属性字段</param>
		/// <param name="asFieldName">别名，如果不指定，则使用字段名称</param>
		/// <returns>Command1</returns>
		public Command1 Min(object field, string asFieldName)
		{
			string currFieldName = CurrentCommand.TakeStackFields();
			return sqlFunction("MIN", currFieldName, asFieldName);
		}

		/// <summary>
		/// Command1表达式之求合计，请在结果实体类中使用PropertyList["字段别名"] 的方式获取查询值
		/// </summary>
		/// <param name="field">属性字段</param>
		/// <param name="asFieldName">别名，如果不指定，则使用字段名称</param>
		/// <returns>Command1</returns>
		public Command1 Sum(object field, string asFieldName)
		{
			string currFieldName = CurrentCommand.TakeStackFields();
			return sqlFunction("SUM", currFieldName, asFieldName);
		}

		/// <summary>
		/// Command1表达式之求平均，请在结果实体类中使用PropertyList["字段别名"] 的方式获取查询值
		/// </summary>
		/// <param name="field">属性字段</param>
		/// <param name="asFieldName">字段别名，如果不指定，则使用字段名称</param>
		/// <returns>Command1</returns>
		public Command1 Avg(object field, string asFieldName)
		{
			string currFieldName = CurrentCommand.TakeStackFields();
			return sqlFunction("AVG", currFieldName, asFieldName);
		}

		private Command1 sqlFunction(string sqlFunctionName, string fieldName, string asFieldName)
		{
			if(string.IsNullOrEmpty(asFieldName))
			{
				if(this.CurrentCommand.haveJoinOpt)
				{
					throw new Exception("有表连接查询的时候，" + sqlFunctionName + " 结果必须指定别名！");
				}
				else
				{
					asFieldName = fieldName;
				}
			}
			//CurrentCommand.sqlFunctionString = sqlFunctionName + "(" + fieldName + ") AS " + asFieldName;
			//上面一行代码被注释,修改成下面的代码,修正在查询中使用多个函数操作的问题
			//感谢网友 泸州-雷皇 2014.10.29 发现并修复该问题
			if(!string.IsNullOrEmpty(CurrentCommand.sqlFunctionString))
			{
				CurrentCommand.sqlFunctionString += ", ";
			}
			CurrentCommand.sqlFunctionString += sqlFunctionName + "(" + fieldName + ") AS " + asFieldName;
			CurrentCommand.sqlFunctionString = sqlFunctionName + "(" + fieldName + ") AS " + asFieldName;
			//asFieldName 必须处理，否则找不到字段。感谢网友Super Show 发现问题 
			if(fieldName == asFieldName)
			{
				this.CurrentCommand.currEntity.SetFieldValue(asFieldName.Trim().TrimStart('[').TrimEnd(']'), 0);
			}
			return this;
		}

		#endregion
	}

	public class Command2 : Command4, ICommand2
	{
		private Command CurrentCommand;

		public Command2(Command command) : base(command)
		{
			CurrentCommand = command;
		}

		public Command3 GroupBy(object field)
		{
			string fieldName = CurrentCommand.TakeOneStackFields().SqlFieldName;
			CurrentCommand.GroupbyFieldNames.Add(fieldName.Trim());
			CurrentCommand.CommandString += "\r\n          GROUP BY " + fieldName;
			return new Command3(CurrentCommand);
		}

		public Command3 GroupBy(object field, params object[] others)
		{
			string strTemp = string.Empty;
			string fieldName = CurrentCommand.TakeOneStackFields().SqlFieldName;
			CurrentCommand.GroupbyFieldNames.Add(fieldName.Trim());
			for(int i = 0; i < others.Length; i++)
			{
				string fieldNameTemp = CurrentCommand.TakeOneStackFields().SqlFieldName;
				CurrentCommand.GroupbyFieldNames.Add(fieldNameTemp.Trim());
				strTemp += "," + fieldNameTemp;
			}
			CurrentCommand.CommandString += "\r\n          GROUP BY " + fieldName + strTemp;
			return new Command3(CurrentCommand);
		}

		public Command4 Having(object field, object Value, string sqlFunctionFormat)
		{
			Command3 q3 = new Command3(CurrentCommand);
			return q3.Having(field, Value, sqlFunctionFormat);
		}

		public Command4 Having(CompareFunc cmpFun)
		{
			Command3 q3 = new Command3(CurrentCommand);
			return q3.Having(cmpFun);
		}
	}

	public class Command3 : Command4, ICommand3
	{
		private Command CurrentCommand;

		public Command3(Command command) : base(command)
		{
			CurrentCommand = command;
		}

		public Command4 Having(object field, object Value, string sqlFunctionFormat)
		{
			if(string.IsNullOrEmpty(sqlFunctionFormat))
			{
				throw new ArgumentNullException("SQL 格式函数不能为空！");
			}
			if(sqlFunctionFormat.Contains("--") || sqlFunctionFormat.Contains("\'"))
			{
				throw new ArgumentException("SQL 格式函数不合法！");
			}
			if(sqlFunctionFormat.Contains("{0}") && sqlFunctionFormat.Contains("{1}"))
			{
				var tnf = CurrentCommand.TakeOneStackFields();
				string fieldName = tnf.Field;
				string paraName = CurrentCommand.CreateParameter(tnf);
				string havingString = string.Format(sqlFunctionFormat, fieldName, paraName);
				CurrentCommand.CommandString += "\r\n             HAVING " + havingString;
				return new Command4(CurrentCommand);
			}
			throw new ArgumentException("SQL 格式函数要求类似这样的格式：SUM({0}) > {1}");
		}

		public Command4 Having(CompareFunc cmpFun)
		{
			Comparer compare = new Comparer(this.CurrentCommand);
			Comparer cmpResult = cmpFun(compare);
			if(!object.Equals(cmpResult, null))
			{
				CurrentCommand.CommandString += "\r\n             HAVING " + cmpResult.WhereString;
			}
			return new Command4(CurrentCommand);
		}
	}

	public class Command4 : ICommand4
	{
		private Command CurrentCommand;

		public Command4(Command command)
		{
			CurrentCommand = command;
		}

		protected internal void AddOrderType(string orderType)
		{
			CurrentCommand.CommandString += orderType;
		}

		public CommandOrderType OrderBy(object field)
		{
			string temp = CurrentCommand.haveOrderBy ? "," : "\r\n                 ORDER BY ";
			CurrentCommand.haveOrderBy = true;
			CurrentCommand.CommandString += temp + CurrentCommand.TakeOneStackFields().SqlFieldName;
			return new CommandOrderType(this);
		}

		public Command4 OrderBy(object field, string orderType)
		{
			string strTemp = orderType.ToLower();
			if(strTemp != "asc" && strTemp != "desc")
			{
				throw new FormatException("排序类型错误！");
			}
			string temp = CurrentCommand.haveOrderBy ? "," : "\r\n                 ORDER BY ";
			CurrentCommand.haveOrderBy = true;
			CurrentCommand.CommandString += temp + CurrentCommand.TakeOneStackFields().SqlFieldName + " " + orderType;
			return this;
		}

		public Command4 OrderBy(SortOrder order)
		{
			string temp = CurrentCommand.haveOrderBy ? "," : "\r\n                 ORDER BY ";
			CurrentCommand.haveOrderBy = true;
			CurrentCommand.CommandString += temp + order.ToString();
			return this;
		}

		public Command4 OrderBy(OrderAction orderAct)
		{
			SortOrder order = new SortOrder(CurrentCommand);
			orderAct(order);
			return OrderBy(order);
		}

		public Command4 OrderBy<T>(OrderAction<T> orderAct) where T : class
		{
			SortOrder order = new SortOrder(CurrentCommand);
			T para = CurrentCommand.GetUsedEntity<T>();
			orderAct(order, para);
			return OrderBy(order);
		}

		/// <summary>
		/// （网友[有事M我]、[左眼]提供）根据传入的实体类的多个属性的排序信息，从而进行动态的排序；
		/// 适用于不能在Command表达式里面直接指明排序方式的场景（比如需要从前台传入）。
		/// </summary>
		/// <param name="orderStr">排序数组，形如{"ID desc","Name asc"}</param>
		/// <returns></returns>
		public Command4 OrderBy(string[] orderStr)
		{
			if(orderStr == null || orderStr.Length <= 0)
			{
				return this;
			}
			string temp = CurrentCommand.haveOrderBy ? "," : "\r\n                 ORDER BY ";
			CurrentCommand.haveOrderBy = true;
			foreach(string str in orderStr)
			{
				string[] tempArr = str.Split(' ');
				string[] orderArr = new string[2];
				string tempArr_0 = tempArr[0].Trim();
				//访问属性名称对应的属性值，得到真正的排序字段
				object Value = CurrentCommand.currEntity[tempArr_0];
				//如果要排序的属性未包含在实体类的属性定义里面，下面将出现异常
				string orderField = CurrentCommand.TakeOneStackFields().SqlFieldName;
				orderArr[0] = tempArr_0;
				if(tempArr.Length == 1)
				{
					orderArr[1] = "ASC";
				}
				else
				{
					if(tempArr[1].Equals("desc", StringComparison.OrdinalIgnoreCase)) //非desc则全部以asc进行排列
					{
						orderArr[1] = "DESC";
					}
					else
					{
						orderArr[1] = "ASC";
					}
				}
				temp = string.Format("{0} {1} {2},", temp, orderField, orderArr[1]);
			}
			CurrentCommand.CommandString += temp.TrimEnd(',');
			return this;
		}

		public Command End()
		{
			return this.CurrentCommand;
		}
	}
}